package 方法句柄;

public class 方法句柄3 {

	public 方法句柄3() {
		// TODO 自动生成的构造函数存根
	}

}
1.JDK何时引入Methedhandle Java7 引入的重要的API，该包提供了一种新的动态调用方法的机制。

2.什么是MethodHandle？
MethodHandle 是对基础方法，构造函数，字段或类似的低级操作的类型化，直接可执行的引用，并带有自变量或返回值的可选转换。 

3.创建和使用MethodHandle，四个步骤:
	（1）创建查找
	（2）创建方法类型
	（3）查找方法句柄
	（4）调用方法句柄

4.MethodHandle 和反射
   从性能的角度来看，由于访问检查是在创建时,而不是在执行时进行的，因此MethodHandle API的速度可能比Reflection API 快得多。
如果存在安全管理器，则这种差异会被放大，因为成员和类查找需要接受其他检查。
   但是如果考虑到性能不是一项任务的唯一适用性衡量指标，我们还必须考虑到，由于缺少诸如成员类枚举，可访问性标志检查等机制，MethodHandlesAPI 难以使用。
尽管如此，但是Methodhandles API 提供了改变参数类型和参数顺序。

5.步骤1-创建查找
   当我们要创建方法句柄时，要做的第一件事是检索查找，工厂对象负责为查找类可见的方法，构造函数和字段创建方法句柄。通过MethodHandles API，可以创建具有不
同访问模式的查找对象。让我们创建提供对公共方法的访问的查找：
   MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
但是，如果我们还希望访问私有方法和受保护的方法，则可以使用lookup（）方法：
   MethodHandles.Lookup lookup = MethodHandles.lookup();

6.步骤2-创建一个MethodType
   为了能够创建MethodHandle，查找对象需要定义其类型，这是通过MethodType类实现的。
   特别是，一个MethodType代表的参数和返回类型接受和方法返回的句柄，或者传递，并通过方法调用者手柄预期。
   MethodType的结构很简单，它由返回类型和适当数量的参数类型组成，必须在方法句柄及其所有调用者之间正确匹配。以同样的方式作为MethodHandle，一个连的情
况下MethodType是不可变的。让我们看看如何定义一个MethodType，该方法将java.util.List类指定为返回类型，并将Object数组指定为输入类型：
   MethodType mt = MethodType.methodType(List.class, Object[].class);
如果该方法返回原始类型或void作为其返回类型，我们将使用表示这些类型的类（void.class，int.class…）。
让我们定义一个MethodType，它返回一个int值并接受一个Object：
   MethodType mt = MethodType.methodType(int.class, Object.class);
现在，我们可以继续创建MethodHandle。

7.步骤3-创建一个MethodHandle
（1）实例方法:
	使用findVirtual（）方法允许我们为对象方法创建MethodHandle。让我们基于String类的concat（）方法创建一个：
	MethodType mt = MethodType.methodType(String.class, String.class);
    MethodHandle concatMH = publicLookup.findVirtual(String.class, "concat", mt);
（2）静态方法:
	当我们想访问静态方法时，可以改用findStatic（）方法：
	MethodType mt = MethodType.methodType(List.class, Object[].class);
	MethodHandle asListMH = publicLookup.findStatic(Arrays.class, "asList", mt);
（3）构造函数:
	可以使用findConstructor（）方法来访问构造函数。让我们创建一个充当Integer类的构造函数的方法句柄，接受一个String属性：
	MethodType mt = MethodType.methodType(void.class, String.class);
	MethodHandle newIntegerMH = publicLookup.findConstructor(Integer.class, mt);
（4）字段使用方法句柄，还可以访问字段。
	public class Book {         
		String id;    
		String title;     
		// constructor 
	}
	MethodHandle getTitleMH = lookup.findGetter(Book.class, "title", String.class);
（5）私有方法:
	可以在java.lang.reflect API 的帮助下为私有方法创建方法句柄。让我们开始向Book类添加一个私有方法：
	private String formatBook(){    
		return id + " > " + title;
	}
	Method formatBookMethod = Book.class.getDeclaredMethod("formatBook");
	formatBookMethod.setAccessible(true); 
	MethodHandle formatBookMH = lookup.unreflect(formatBookMethod);
8.步骤4-调用方法句柄
	创建方法句柄后，下一步就是使用它们。特别是，MethodHandle类提供了三种执行方法句柄的方法：invoke（），invokeWithArugments（）和invokeExact（）。
（1）invoke方法当使用invoke（）方法时，我们强制执行固定数量的参数（arity），但允许对参数和返回类型进行强制转换和装箱/拆箱。让我们看一下如何在框内
	的参数中使用invoke（）：
	MethodType mt = MethodType.methodType(String.class, char.class, char.class);
	MethodHandle replaceMH = publicLookup.findVirtual(String.class, "replace", mt);
	String output = (String) replaceMH.invoke("jovo", Character.valueOf('o'), 'a'); 
	assertEquals("java", output);
（2）invokeWithArguments方法
	使用invokeWithArguments方法调用方法句柄是这三个选项中限制最少的。实际上，除了对参数和返回类型进行强制转换和装箱/拆箱外，它还允许可变参数数组传入作为
	方法参数集合调用。来到实践中，这允许我们创建一个列表的整数从开始阵列的INT值：
	MethodType mt = MethodType.methodType(List.class, Object[].class);
	MethodHandle asList = publicLookup.findStatic(Arrays.class, "asList", mt);
	List<Integer> list = (List<Integer>) asList.invokeWithArguments(1,2);
	assertThat(Arrays.asList(1,2), is(list));
（3）invokeExact方法:
	如果我们希望在执行方法句柄（参数数量及其类型）方面受到更多限制，则必须使用invokeExact（）方法。实际上，它不提供对提供的类的任何强制转换，并且需要固定数
	量的参数。让我们看看如何使用方法句柄求和两个int值：
	MethodType mt = MethodType.methodType(int.class, int.class, int.class);
	MethodHandle sumMH = lookup.findStatic(Integer.class, "sum", mt);
	int sum = (int) sumMH.invokeExact(1, 11);
	assertEquals(12, sum);
9.重要举例:
	MethodHandle.invoke()并且MethodHandle.invokeExact()是特殊方法，其行为与其他可变arity方法不同：
	与虚拟方法一样，源级调用invokeExact和invoke编译一条invokevirtual指令。更不寻常的是，编译器必须记录实际的参数类型，并且不能对arguments执行方法
	调用转换。相反，它必须根据它们自己未转换的类型将它们压入堆栈。方法句柄对象本身在参数之前被压入堆栈。然后，编译器使用符号类型描述符来调用方法句柄，该符号类
	型描述符描述了参数和返回类型。因此，当您调用这些方法时，参数的类型确实很重要。如果要将参数作为传递Object[]，
	则应invokeWithArguments()改用：mh.invokeWithArguments(myArray);
10.总结总结这三个方法的差异：
	invoke，invokeExact 传入参数时，必须与方法签名参数是一致的，不能以参数合成数组进行传递重要的是invoke 方法可以提供参数自动装箱与拆箱，
	但是invokeExact 则必须是精确的参数类型，不能进行自动的装箱拆箱。invokeWithArguments 方法调用则可以Object[] 数组的形式进行调用

